#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <time.h>
#include <string.h>

// 定义游戏棋盘大小
#define BOARD_SIZE 3

// 定义玩家符号
#define PLAYER_X 'X'
#define PLAYER_O 'O'
#define EMPTY ' '

// 游戏模式
typedef enum {
    MODE_PVP = 1,    // 双人对战
    MODE_PVC = 2     // 玩家vs电脑
} GameMode;

// 全局变量
char board[BOARD_SIZE][BOARD_SIZE];
char current_player = PLAYER_X;
GameMode game_mode;
bool is_ai_turn = false;

// 函数声明
void init_board();
void print_board();
bool make_move(int row, int col);
bool check_winner();
bool is_board_full();
void switch_player();
int get_player_move();
void ai_move();
int minimax(char board[BOARD_SIZE][BOARD_SIZE], int depth, bool is_maximizing);
int evaluate_board();
GameMode select_game_mode();
void print_welcome();

int main() {
    srand(time(NULL)); // 初始化随机数种子
    
    print_welcome();
    game_mode = select_game_mode();
    init_board();
    
    printf("\n游戏开始！");
    if (game_mode == MODE_PVC) {
        printf("您是 X，电脑是 O\n");
    } else {
        printf("双人对战模式\n");
    }
    printf("玩家 X 先手\n\n");
    
    while (true) {
        print_board();
        
        if (game_mode == MODE_PVC && current_player == PLAYER_O) {
            // 电脑回合
            printf("电脑正在思考...\n");
            ai_move();
            printf("电脑选择了一个位置\n");
        } else {
            // 玩家回合
            printf("当前玩家: %c\n", current_player);
            int position = get_player_move();
            int row = (position - 1) / BOARD_SIZE;
            int col = (position - 1) % BOARD_SIZE;
            
            if (!make_move(row, col)) {
                printf("❌ 无效移动！该位置已被占用。\n");
                continue;
            }
        }
        
        // 检查游戏结束条件
        if (check_winner()) {
            print_board();
            if (game_mode == MODE_PVC && current_player == PLAYER_O) {
                printf("💻 电脑获胜！再接再厉！\n");
            } else if (game_mode == MODE_PVC && current_player == PLAYER_X) {
                printf("🎉 恭喜您获胜！\n");
            } else {
                printf("🎉 玩家 %c 获胜！\n", current_player);
            }
            break;
        }
        
        if (is_board_full()) {
            print_board();
            printf("🤝 平局！棋盘已满。\n");
            break;
        }
        
        switch_player();
    }
    
    printf("\n感谢游戏！\n");
    return 0;
}

// 打印欢迎信息
void print_welcome() {
    printf("=====================================\n");
    printf("         🎮 井字棋游戏 🎮\n");
    printf("=====================================\n");
    printf("游戏规则：\n");
    printf("• 在3x3棋盘上轮流下棋\n");
    printf("• 率先在横向、纵向或对角线连成一线者获胜\n");
    printf("• 支持玩家对战电脑或双人对战\n");
    printf("• 输入1-9选择位置\n");
    printf("=====================================\n\n");
}

// 选择游戏模式
GameMode select_game_mode() {
    int choice;
    printf("请选择游戏模式：\n");
    printf("1. 双人对战 (玩家 vs 玩家)\n");
    printf("2. 单人游戏 (玩家 vs 电脑)\n");
    printf("请输入选择 (1-2): ");
    
    while (scanf("%d", &choice) != 1 || (choice != 1 && choice != 2)) {
        printf("❌ 无效选择！请输入 1 或 2: ");
        while (getchar() != '\n'); // 清除输入缓冲区
    }
    
    return (GameMode)choice;
}

// 初始化游戏棋盘
void init_board() {
    for (int i = 0; i < BOARD_SIZE; i++) {
        for (int j = 0; j < BOARD_SIZE; j++) {
            board[i][j] = EMPTY;
        }
    }
}

// 打印游戏棋盘
void print_board() {
    printf("\n");
    printf("     1   2   3\n");
    for (int i = 0; i < BOARD_SIZE; i++) {
        printf("  %d  %c | %c | %c \n", i + 1, board[i][0], board[i][1], board[i][2]);
        if (i < BOARD_SIZE - 1) {
            printf("    -----------\n");
        }
    }
    printf("\n");
    
    // 显示位置提示
    printf("位置对应图：\n");
    printf("     1   2   3\n");
    for (int i = 0; i < BOARD_SIZE; i++) {
        printf("  %d  %d | %d | %d \n", i + 1, 
               i * BOARD_SIZE + 1, 
               i * BOARD_SIZE + 2, 
               i * BOARD_SIZE + 3);
        if (i < BOARD_SIZE - 1) {
            printf("    -----------\n");
        }
    }
    printf("\n");
}

// 执行移动
bool make_move(int row, int col) {
    if (row >= 0 && row < BOARD_SIZE && col >= 0 && col < BOARD_SIZE && board[row][col] == EMPTY) {
        board[row][col] = current_player;
        return true;
    }
    return false;
}

// 检查是否有玩家获胜
bool check_winner() {
    // 检查行
    for (int i = 0; i < BOARD_SIZE; i++) {
        if (board[i][0] == current_player && 
            board[i][1] == current_player && 
            board[i][2] == current_player) {
            return true;
        }
    }
    
    // 检查列
    for (int j = 0; j < BOARD_SIZE; j++) {
        if (board[0][j] == current_player && 
            board[1][j] == current_player && 
            board[2][j] == current_player) {
            return true;
        }
    }
    
    // 检查对角线
    if (board[0][0] == current_player && 
        board[1][1] == current_player && 
        board[2][2] == current_player) {
        return true;
    }
    
    if (board[0][2] == current_player && 
        board[1][1] == current_player && 
        board[2][0] == current_player) {
        return true;
    }
    
    return false;
}

// 检查棋盘是否已满
bool is_board_full() {
    for (int i = 0; i < BOARD_SIZE; i++) {
        for (int j = 0; j < BOARD_SIZE; j++) {
            if (board[i][j] == EMPTY) {
                return false;
            }
        }
    }
    return true;
}

// 切换玩家
void switch_player() {
    current_player = (current_player == PLAYER_X) ? PLAYER_O : PLAYER_X;
}

// 获取玩家输入
int get_player_move() {
    char input[100];
    int row, col, position;
    
    printf("请输入位置 (行-列格式如2-2): ");
    
    while (1) {
        if (fgets(input, sizeof(input), stdin) == NULL) {
            printf("❌ 输入错误！请重新输入: ");
            continue;
        }
        
        // 去除字符串末尾的换行符
        input[strcspn(input, "\n")] = 0;
        
        // 跳过空输入
        if (strlen(input) == 0) {
            printf("❌ 输入不能为空！请重新输入: ");
            continue;
        }
        
        // 尝试解析 "行-列" 格式（如 2-2）
        if (sscanf(input, "%d-%d", &row, &col) == 2) {
            if (row >= 1 && row <= 3 && col >= 1 && col <= 3) {
                position = (row - 1) * 3 + col;
                printf("✅ 您选择了第%d行第%d列（位置%d）\n", row, col, position);
                return position;
            } else {
                printf("❌ 行列数字必须在1-3之间！请重新输入: ");
                continue;
            }
        }
        
        // 尝试解析单个数字格式（1-9）
        if (sscanf(input, "%d", &position) == 1) {
            if (position >= 1 && position <= 9) {
                row = (position - 1) / 3 + 1;
                col = (position - 1) % 3 + 1;
                printf("✅ 您选择了位置%d（第%d行第%d列）\n", position, row, col);
                return position;
            } else {
                printf("❌ 位置编号必须在1-9之间！请重新输入: ");
                continue;
            }
        }
        
        printf("❌ 输入格式错误！请输入位置编号(1-9)或行-列格式(如2-2): ");
    }
}

// AI移动 - 使用Minimax算法
void ai_move() {
    int best_score = -1000;
    int best_row = -1, best_col = -1;
    
    // 遍历所有可能的移动
    for (int i = 0; i < BOARD_SIZE; i++) {
        for (int j = 0; j < BOARD_SIZE; j++) {
            if (board[i][j] == EMPTY) {
                // 尝试移动
                board[i][j] = PLAYER_O;
                int score = minimax(board, 0, false);
                board[i][j] = EMPTY; // 撤销移动
                
                if (score > best_score) {
                    best_score = score;
                    best_row = i;
                    best_col = j;
                }
            }
        }
    }
    
    // 执行最佳移动
    if (best_row != -1 && best_col != -1) {
        board[best_row][best_col] = PLAYER_O;
    }
}

// Minimax算法实现
int minimax(char board[BOARD_SIZE][BOARD_SIZE], int depth, bool is_maximizing) {
    int score = evaluate_board();
    
    // 如果游戏结束，返回评分
    if (score == 10) return score - depth;  // AI胜利
    if (score == -10) return score + depth; // 玩家胜利
    if (is_board_full()) return 0;          // 平局
    
    if (is_maximizing) {
        // AI回合，寻找最大值
        int best = -1000;
        for (int i = 0; i < BOARD_SIZE; i++) {
            for (int j = 0; j < BOARD_SIZE; j++) {
                if (board[i][j] == EMPTY) {
                    board[i][j] = PLAYER_O;
                    best = (best > minimax(board, depth + 1, false)) ? best : minimax(board, depth + 1, false);
                    board[i][j] = EMPTY;
                }
            }
        }
        return best;
    } else {
        // 玩家回合，寻找最小值
        int best = 1000;
        for (int i = 0; i < BOARD_SIZE; i++) {
            for (int j = 0; j < BOARD_SIZE; j++) {
                if (board[i][j] == EMPTY) {
                    board[i][j] = PLAYER_X;
                    best = (best < minimax(board, depth + 1, true)) ? best : minimax(board, depth + 1, true);
                    board[i][j] = EMPTY;
                }
            }
        }
        return best;
    }
}

// 评估棋盘状态
int evaluate_board() {
    // 检查所有获胜条件
    
    // 检查行
    for (int i = 0; i < BOARD_SIZE; i++) {
        if (board[i][0] == board[i][1] && board[i][1] == board[i][2]) {
            if (board[i][0] == PLAYER_O) return 10;
            if (board[i][0] == PLAYER_X) return -10;
        }
    }
    
    // 检查列
    for (int j = 0; j < BOARD_SIZE; j++) {
        if (board[0][j] == board[1][j] && board[1][j] == board[2][j]) {
            if (board[0][j] == PLAYER_O) return 10;
            if (board[0][j] == PLAYER_X) return -10;
        }
    }
    
    // 检查对角线
    if (board[0][0] == board[1][1] && board[1][1] == board[2][2]) {
        if (board[0][0] == PLAYER_O) return 10;
        if (board[0][0] == PLAYER_X) return -10;
    }
    
    if (board[0][2] == board[1][1] && board[1][1] == board[2][0]) {
        if (board[0][2] == PLAYER_O) return 10;
        if (board[0][2] == PLAYER_X) return -10;
    }
    
    return 0; // 无胜负
} 